Coercion (型別轉換)其實最令人煩惱的不是 一元運算子的 + 或是 加法運算子的 多載問題。
其實最多人一開始採的坑是 Equality (相等) 問題。
以下是最常見的描述:
兩個 ==
一般相等 比較 值
。三個 ===
是嚴格相等,比較 值
和 型別
。但很抱歉,這樣寫都是錯的。
這邊是 Spec.
第一行
== 一般相等
等效 === 嚴格相等
也就是說,如果你了解 code 裡面寫的型別都一樣,可以放心用 == 一般相等
如果型別不同,直接回傳 False
(也就是連值
都 不會比較
)
先比較數字型別
的狀況
(a.) (b.) 實作 IEEE 754 定義 (NaN ≠ x) = false.
之前有寫過 NaN,參考
[day06] YDKJS (Type) : 特殊值:undefined / undeclared / TDZ ? , NaN , 負數 0
值
相等就回傳 true之前有寫過 負數 0,參考
[[day06] YDKJS (Type) : 特殊值:undefined / undeclared / TDZ ? , NaN , 負數 0]
嚴格相等( === )大家從小就會,補充閱讀 Spec.
Null , undefined
可以繼續比較一定同型別,且該型別只有一個值,當然會相等
string
要相同的長度
和相同的字元對應相同的位置
才會回傳 trueBoolean
只有兩個值,比對是否相等很容易Symbol
Symbol value 一樣才會回傳 trueObject
太多問題,不建議做比對。(自己挖掘 Spec. 這邊不深入)
== 允許在等價性比較中進行強制轉換,而 === 不允許強制轉換
。一般相等(==)
,因為它不可預測 ?一個簡單的問題,如果不能預測,那 JavaScript 語言要怎麼實作?
量子 JavaScript ? 沒觀察就處於疊加態 ? ( 老高看太多 XDDD )
不如這樣說,
先學會
,再來考慮要不要使用。這一直是這個系列主題的宗旨:打造全新 JavaScript Mindset ,而不是一律使用 嚴格相等(===)
就不用學。
順帶一提,
如果你只使用 嚴格相等(===)
,沒認真思考過你寫的 code 其值與型別,
那麼得到 false
,你會不知道其實這邊得到的 false 有兩個意涵:
型別不一樣
。型別一樣
,但其Equality comparison 失敗
。所以,還是認真學習 一般相等(==)
a.k.a. 抽象等價性
(之前說過型別轉換可以視為隱藏細節的抽象
),把目光放在 「抽象等價性」的 Equality comparison。
「之前」參考以下文章
[day10] YDKJS (Coercion) : 如何決定何時使用「顯性」或是「隱性」的型別轉換?
一般相等 Spec. Abstract Equality Comparison 7.2.14
line 2, 3
JavaScript 在 抽象等價性
的比對上, null , undefined 把兩者視為相等。
有時候可能你會用 null , 有些人可能用 undefined 。
或是你只是單純想知道,是不是設定清除賦值的 undefined, null 狀態。
在某些時候,這兩個值他們會不一樣,但至少做 比對(==) 時視為相等,不用去思考那個很複雜的 ToPrimitive()
。
參考以下例子
你可以用抽象等價性
來查看一個屬性的「值」是不是 設定為空或是沒有初始值,
如果你用 嚴格相等
,你要把所有的狀況都寫上去,因為 null 和 undefined 型別不同
。
如果你用 抽象等價性
,可以把你的 code 寫比較簡潔。
(用 null
而不使用 undefined
只是純粹因為字可以打比較少 XDDDD )
ESLine 好像會提示,Kyle Simpson 有調整這一個 rule,best tools are the ones that are most configurable
之前有寫過
undefined 典型用法是:
1 .變數被宣告了,但沒有賦值時,就等於 undefined。
2. 呼叫函式時,應該提供的引數沒有提供,該引數等於 undefined。3. 物件沒有沒有賦值的屬性,該屬性的值為 undefined。
4. 函式沒有回傳值時,預設回傳 undefined。
[day05] YDKJS (Type) : 初學者第一坑 - typeof 運算子, 詳解 undefined
line 4 ~ 7
ToNumber()
string
=> ToNumber() 之後做數字相等運算 (numeric comparison)boolean
=> ToNumber() 之後做比對 ! ToNumber(x) == y.
或是 x == ! ToNumber(y).
再複習一下 ToNumber()
- 空字串變成
0
- false -> 0 , true -> 1
reference:
[day08] YDKJS (Coercion:spec) : 回來讀 spec. ToString(), ToNumber() , ToBoolean()
參考以下例子
我自己經驗是,有時候 element.value 可能是字面值的數字(type 還是 string: "1"
),
但是如果要做比較還要做型別轉換 (比如 + 一元運算子
會做 ToNumber()
)。
其實在這個例子中,不用像是 line 4 做轉換,可以放心使用 抽象等價性 ( == )
line 8,line 9 : top level objects type 都會做 ToPrimitive()
抽象等價性
依然做偏好數字
的運算。註:不要忘記兩邊都是 object -> 型別一樣就是演算法第一行,執行 === 嚴格相等
Primitive value:
不要忘記, ToPrimitive() 是第一個講的 abstract operations
reference
[day07] YDKJS (Type/Coercion) : Type總結 和 abstract operations (Spec.)
抽象等價性 ( == )
因為只會給你自己帶來麻煩。
範例如下:
拆解步驟:
line 5 : 先 ToPrimitive()
line 6 : 抽象等價性 偏好ToNumber()
=> 轉成數字。
順帶一提,拿 array
和 數字
做比較
,程式可以寫得出來(因為電腦可以讀,不會報錯),
但這樣寫的背後意義不符合邏輯,沒有任何原因出現這樣的 code。
如果有,請仔細思考情境,最好適度重構。
而不是使用 嚴格相等 ===
來逃避重構這些不合邏輯且沒有意義的 code。
從邏輯上也應該只有 Primitive 會做比對
。
無論任何時候,避免對 non-Primitive 做「任何比對」。
一個會有 non-Primitive 可以做 抽象等價性 ( == ) 的歷史原因,
是因為很早期習慣用 new 關鍵字產生 string , number 。
這些透過 new 產生的結果要 ToPrimitive() 才做 抽象等價性 ( == )
。
但是這個用法已經非常不建議使用,所以不會有這個情境了。
明天的文章會延續今天主題,以 Corner Cases 整理,或是說練習為主。